//  Author: Justin Cowen
//  Purpose: Algovision System - Matrix Class
//           According to the Class Diagram in Documentation


public class Matrix {
	double userInput;
	double defaultInput;
	
	
	
	//Wasn't sure whether or not to actually return values, or void.
	//minor thing to look at later
	
	
	
	static double [][] matrixCopy(double [][]A){
		double [][] C = new double [A.length][A[0].length];
		for(int i=0; i<A.length; i++){
			for(int j=0; j<A[0].length; j++){
				C[i][j]=A[i][j];
			}
		}
		return C;
	}
	
	public static void matrixAdd(double [][]A, double [][]B){
		double [][]C = new double [A.length] [A[0].length];
		if(A.length == B.length && A[0].length == B[0].length){
			for(int i=0; i<A.length; i++){
				for(int j=0; j<A[0].length; j++){
					C[i][j] = A[i][j]+ B[i][j];
				}
			}
			//return C
		}
		else{
			System.out.println("Cannot add Matrices (incompatible)");
			//return null
		}
	}
	
	public static void matrixSubtract(double [][]A, double [][]B){
		double [][]C = new double [A.length] [A[0].length];
		if(A.length == B.length && A[0].length == B[0].length){
			for(int i=0; i<A.length; i++){
				for(int j=0; j<A[0].length; j++){
					C[i][j] = A[i][j] - B[i][j];
				}
			}
			//return C;
		}
		else{
			System.out.println("Cannot subtract Matrices (incompatible)");
			//return null;
		}
	}
	
	public static void matrixMultiply(double [][]A, double [][]B){
		double [][]C = new double[A.length][B[0].length];
		if(A[0].length==B.length){
			for(int i=0; i<A.length; i++){
				for(int j=0; j<B[0].length; j++){
					for(int k=0; k<A[0].length; k++){
						C[i][j]+= A[i][k]*B[k][j];
					}
				}
			}
			//return C;
		}
		else{
			System.out.println("Cannot multiply Matrices");
			//return null;
		}
	}
	
	public static void matrixScalar(double [][]A, double scalar){
		double [][]C = new double[A.length][A[0].length];
		for(int i=0; i<A.length; i++){
			for(int j=0; j<A[0].length; j++){
				C[i][j] = A[i][j]*scalar;
			}
		}
		//return C;		
	}
	
	public static void matrixIdentity(int size){
		double [][]C = new double[size][size];
		for(int i=0; i<size; i++){
			for(int j=0; j<size; j++){
				if(i==j)
					C[i][j]=1;
				else
					C[i][j]=0;
			}
		}
		//return C;
	}
	
	public static void matrixZero(int size){
		double [][]C = new double[size][size];
		for(int i=0; i<size; i++){
			for(int j=0; j<size; j++){
				C[i][j]=0;
			}
		}
		//return C;
	}
	
	public static double [][] matrixRowswap(int row1, int row2, double [][]A){
		double [][]C = new double[A.length][A[0].length];
		double [] temp = new double [A[0].length];
		if(row1 >= A.length || row2 >= A.length){
			System.out.println("Cannot swap rows");
			return null;
		}
		else{
			//Transfer all rows except swap row
			for(int i=0; i<A.length; i++){
				for(int j=0; j<A[0].length; j++){
					if(i==row1){
						temp[j]= A[i][j];
					}
					else{
						if(i==row2){
							C[row1][j] = A[i][j];
						}
						else
							C[i][j] = A[i][j];
					}
					
				}
			}
			//Put swap row back into matrix
			for(int j=0; j<A[0].length; j++){
				C[row2][j] = temp[j];
			}
			return C;
		}
	}
	
	public static double [][] matrixRowMultiply(int row, double scalar, double [][]A){
		if(row < A.length){
			for(int i=0; i<A[0].length; i++){
				A[row][i] = A[row][i]*scalar;
			}
			return A;
		}
		else{
			System.out.println("Cannot Multiply Row (Row does not exist)");
			return null;
		}
	}
	
	public static double [][] matrixAugment(double [][]A, double [][]B){
		int columns = A[0].length+B[0].length;
		double [][]C = new double[A.length][columns];
		for(int i=0; i<A.length; i++){
			for(int j=0; j<columns; j++){
				if(j>=A.length){
					C[i][j] = B[i][j-(A[0].length)];
				}
				else
					C[i][j] = A[i][j];
			}
		}
		return C;
	}
	
	static int computePivot(double [][]A, int j, int p, int n){
		while(p<n){
			for(int i =j;i<n; i++){
				if(Math.abs(A[i][j]) > Math.abs(A[p][j])){
					p = i;
				}
			}
			break;
		}
		return p;
	}

	
	public static void GaussJordanElim(double [][]A, double [][]B){
		int n = A.length; 
		int E = 1;
		int p;
		
		double[][]C = new double[n][n+1];
		C = matrixAugment(A, B);
		
		for(int j=0; j<n; j++){
			p = j;
			p = computePivot(C, j, p, n);
			if(C[p][j]==0){
				E=0; 
				System.out.println("\nNo unique solution, E=0, exiting");
				//return null;
			}
			else{
				if(p>j){
					C = matrixRowswap(j, p, C);
				}
				C = matrixRowMultiply(j, (1/C[j][j]), C);
				for(int i=0; i<n; i++){
					if(i != j){
						double temp = C[i][j];
						for(int k=j; k<C[0].length; k++){
							C[i][k] -= temp*C[j][k];
						}
					}
				}
			}
		}
		//return C;
	}
	
	public static void matrixPrint(double [][]A){
		if(A ==null){
			System.out.println("No Matrix to Print\n");
		}
		else{
			for(int i=0; i<A.length; i++){
				for(int j=0; j<A[0].length; j++){
					System.out.print(A[i][j]+"\t");
				}
				System.out.println();
			}
		}
	}
}
 